/**
质押相关逻辑代码
*/
package service

import (
	"database/sql"
	"errors"
	"github.com/jmoiron/sqlx"
	"strconv"
	"time"
	"zimuzu_cvn_web_api/config"
	"zimuzu_cvn_web_api/model"
	"zimuzu_cvn_web_api/pkg/drive/db"
	"zimuzu_cvn_web_api/pkg/drive/redis"
	"zimuzu_cvn_web_api/pkg/e"
	"zimuzu_cvn_web_api/pkg/errno"
)

// 质押
// Auth：hzp
// 事务操作：
//   1、cvn_log 增加一条记录  cvn -188  source 7
//   2、user_amount 更新记录 unwithdrawn_cvn - 188    pledging_cvn + 188
func Pledge(Uid int64, cvn float64, plType int) (err error) {

	nxCacheKey := "cvn:pledge:" + strconv.FormatInt(Uid, 10)
	res, err := redis.RedisSetnx(nxCacheKey, "1", 5)
	if err != nil || !res {
		return errors.New("操作过于频繁，请稍后再试")
	}

	//账户信息
	cvbAmount, err := GetUserCvnAmountByUid(Uid)
	if err != nil {
		return
	}

	newBalance := cvbAmount.Balance - cvn
	if newBalance < 0 {
		return errno.WalletNotEnoughERR
	}
	conn, _ := config.C.DB.DB.Beginx()
	//生成CVNT流水记录，修改账户
	updateAmountData := UpdateCvnAmountParams{
		Uid:          Uid,
		Amount:       -cvn,
		Source:       model.LogSourcePledgeDeposit,
		FrozenAmount: cvn,
	}
	_, err = UpdateCvnAmountBalance(conn, updateAmountData)
	if err != nil {
		conn.Rollback()
		return
	}
	//更新不可用资产表信息
	err = UpdateCvnFrozenAmount(conn, Uid, cvn, 0, plType)
	if err != nil {
		conn.Rollback()
		return
	}

	err = conn.Commit()
	if err != nil {
		conn.Rollback()
		return
	}
	return
}

func CvntPledgeDraw() {
	e.Log("info", "开始提取业务。。。。。。。")
	Draw(model.PledgeLinux)
	Draw(model.PledgeToken)
	Draw(model.PledgeDeposit)
}

// 提取 处理队列任务
// Auth：hzp
func Draw(pledgeType int) {

	var cacheKey string
	if pledgeType == model.PledgeDeposit {
		cacheKey = e.UserRedisPrefix + e.RedisTokenDepositListKey
	} else if pledgeType == model.PledgeToken {
		cacheKey = e.UserRedisPrefix + e.RedisTokenDrawListKey
	} else if pledgeType == model.PledgeLinux {
		e.Log("info", "开始处理质押提取业务数据")
		cacheKey = e.UserRedisPrefix + e.RedisDrawUnPledgeListKey + ":linux"
	}

	timeInt64 := time.Now().Unix()
	TaskIdList, err := redis.ZRangeByScore(cacheKey, 0, timeInt64)
	if err != nil {
		e.Log("info", "处理的队列失败 Err=", err.Error())
		return
	}
	e.Log("info", "处理的队列为")
	e.Log("info", TaskIdList)

	if len(TaskIdList) > 0 {
		e.Log("Info", "定时任务开始处理：提取到账业务")
	}

	var TaskIdErrList []int64
	for _, taskIds := range TaskIdList {
		e.Log("info", "TaskID = ", taskIds)
		taskId, err := strconv.ParseInt(taskIds, 10, 64)
		if err != nil {
			continue
		}
		Task, err := model.GetUserDrawTask(taskId)
		if err != nil {
			continue
		}
		err = DoDrawTask(Task, pledgeType)
		if err != nil {
			e.Log("err", err.Error())
			TaskIdErrList = append(TaskIdErrList, taskId)
		}
	}

	// 处理掉已处理的数据
	_, _ = redis.ZRemRangeBySCORE(cacheKey, 0, timeInt64)
	// 将未处理完成的数据写入到redis
	if len(TaskIdErrList) > 0 {
		for _, IdInt64 := range TaskIdErrList {
			_, err = redis.ZAdd(cacheKey, strconv.FormatInt(IdInt64, 10), timeInt64)
			if err != nil {
				e.Log("err", "[TaskId]", IdInt64, " work error.")
			}
		}
	}
}

// 单个提取任务处理
// Auth：hzp
func DoDrawTask(Task model.DrawTaskModel, pledgeType int) (err error) {

	// 事务处理
	err = DrawDB(Task.UID, Task.Cvn, pledgeType)
	if err != nil {
		return err
	}

	// 处理完成之后更新数据库字段为已处理
	err = model.SetDoneDrawTask(config.C.DB.DB, Task.TaskId)
	if err != nil {
		e.Log("err", "[SetDoneDrawTask] ", Task.TaskId, " set done error.")
	}

	// 如果解除质押 会更新用户节点信息
	e.Log("info", "单个处理任务：pledgeType=", pledgeType, " &RelationId=", Task.RelationId)
	if pledgeType == model.PledgeLinux && Task.RelationId > 0 {
		// 解除质押会 更新节点状态
		err = model.UpdateMgNodeUnPledge(Task.RelationId)
		if err != nil {
			e.Log("info", "[Set MgNodeUnPledge] TaskId=", Task.TaskId, " &NodeId=", Task.RelationId, " SET UnPledge error.")
		}
	}

	return nil
}

// 提取
// Auth：hzp
func DrawTask(Uid, relationId int64, cvn float64, pledgeType int) (err error) {

	nxCacheKey := "cvn:draw:" + strconv.FormatInt(Uid, 10)
	res, err := redis.RedisSetnx(nxCacheKey, "1", 5)
	if err != nil || !res {
		return errors.New("操作过于频繁，请稍后再试")
	}

	Available, err := GetPledgeAvailable(Uid, pledgeType)
	if err != nil {
		return err
	}

	checkData, err := CheckRentTokenPledgeStatus(Uid, 0)
	if err != nil {
		return err
	}
	if Available-cvn < 0 {
		return errno.WalletNotEnoughERR
	}
	if checkData.Status == 2 && checkData.Cvn-cvn < 0 {
		return errors.New("可提现余额不足，提取失败")
	}
	// 增加事务    xu
	conn, err := config.C.DB.DB.Beginx()
	err = PledgeDraw(conn, Uid, cvn, pledgeType, relationId)
	if err != nil {
		err = conn.Rollback()
		return
	}

	err = conn.Commit()
	if err != nil {
		_ = conn.Rollback()
		return errno.RollBackErr
	}

	// 清理用户看板数据缓存
	CleanUserNodeBoardDataCache(Uid)
	return nil
}

// 获取 质押、提取 余额
// 质押提取的可用余额
// Auth: hzp
func GetPledgeAvailable(uid int64, pledgeType int) (Available float64, err error) {
	cvnAmount, err := GetUserCvnAmountByUid(uid)
	if err != nil {
		return Available, nil
	}

	// 提取
	userFrozen, err := model.GetCvnFrozenInfo(uid, pledgeType)
	if err != nil {
		err = errors.New("查询质押资产详情出错")
		return
	}
	if cvnAmount.FrozenBalance < userFrozen.Amount {
		err = errors.New("质押资产异常")
		return
	}
	Available = userFrozen.Amount

	return
}

//质押、锁仓提取到账
//Auth:Xu
func DrawDB(uid int64, cvn float64, pledgeType int) (err error) {
	var source int
	if pledgeType == model.PledgeDeposit {
		source = model.LogSourceDepositToken
	} else if pledgeType == model.PledgeToken {
		source = model.LogSourceSaleToken
	} else if pledgeType == model.PledgeLinux {
		source = model.LogSourcePledgeRedemption
	} else {
		return errors.New("提取类型异常")
	}
	e.Log("info", "处理任务：Uid 【", uid, "】")

	// 开启事务
	conn, err := config.C.DB.DB.Beginx()
	if err != nil {
		return err
	}
	//生成CVNT流水记录，修改账户
	updateAmountData := UpdateCvnAmountParams{
		Uid:          uid,
		Amount:       cvn,
		Source:       source,
		FrozenAmount: -cvn,
	}
	_, err = UpdateCvnAmountBalance(conn, updateAmountData)
	if err != nil {
		conn.Rollback()
		return
	}
	//修改冻结资产质押待赎回金额
	err = UpdateCvnFrozenAmount(conn, uid, 0, -cvn, pledgeType)
	if err != nil {
		conn.Rollback()
		return
	}

	// 提交事务
	err = conn.Commit()
	return
}

//修改冻结资产金额
//Auth: Xu
func UpdateCvnFrozenAmount(conn sqlx.Execer, uid int64, amount float64, frozenAmount float64, source int) (err error) {
	userFrozen, err := model.GetCvnFrozenInfo(uid, source)
	if err != nil && err != sql.ErrNoRows {
		return errors.New("查询冻结资产详情失败")
	} else if err == sql.ErrNoRows {
		if amount < 0 {
			return errors.New("质押资产异常")
		}
		userFrozenData := model.CvnFrozenDB{
			UID:          uid,
			Amount:       amount,
			FrozenAmount: frozenAmount,
			Source:       source,
			CreateTime:   time.Now().Unix(),
		}
		err = model.InsertCvnFrozen(conn, userFrozenData)
		if err != nil {
			return errors.New("修改质押资产出错")
		}
	} else if err == nil {
		newAmount := userFrozen.Amount + amount
		newFrozenAmount := userFrozen.FrozenAmount + frozenAmount
		if newAmount < 0 || newFrozenAmount < 0 {
			return errors.New("质押资产可提取数额不足")
		}
		err := model.UpdateCvnFrozenAmount(conn, newAmount, newFrozenAmount, uid, source)
		if err != nil {
			return errors.New("修改质押资产出错2")
		}
	} else {
		return errors.New("未知参数错误")
	}

	return
}

//质押提取，开启锁仓
//Auth:Xu
func PledgeDraw(conn *db.TxLogger, uid int64, amount float64, source int, relationId int64) (err error) {
	var cacheKey string
	var drawTime int64
	timeInt64 := time.Now().Unix()
	if source == model.PledgeDeposit {
		cacheKey = e.UserRedisPrefix + e.RedisTokenDepositListKey
		drawTime = timeInt64 + 1
	} else if source == model.PledgeToken {
		cacheKey = e.UserRedisPrefix + e.RedisTokenDrawListKey
		drawTime = timeInt64 + 72*3600
	} else if source == model.PledgeLinux {
		cacheKey = e.UserRedisPrefix + e.RedisDrawUnPledgeListKey + ":linux"
		drawTime = timeInt64 + 24*3600*7
		//drawTime = timeInt64 + 17
	} else {
		return errors.New("提取类型异常")
	}
	//添加提取任务，定时提取
	taskId, err := model.AddDrawTask(conn, uid, drawTime, relationId, amount, source)
	if err != nil {
		err = errno.DrawTaskError
		return
	}

	runFrozen := 1 // 是否变更不可用资产信息
	var updateAmount, updateFrozenAmount float64
	if source == model.PledgeToken {
		updateFrozenAmount = amount
	} else if source == model.PledgeLinux {
		// 解除质押，此时不扣质押币
		runFrozen = 0
	} else {
		updateAmount = -amount
		updateFrozenAmount = amount
	}
	// 更新不可用资产表信息
	if runFrozen == 1 {
		err = UpdateCvnFrozenAmount(conn, uid, updateAmount, updateFrozenAmount, source)
		if err != nil {
			return
		}
	}

	if source == model.PledgeToken {
		// 生成CVNT流水记录，修改账户
		updateAmountData := UpdateCvnAmountParams{
			Uid:          uid,
			Amount:       0,
			FrozenAmount: amount,
		}
		_, err = UpdateCvnAmountBalance(conn, updateAmountData)
		if err != nil {
			return
		}
	}

	// 更新redis
	InsIdStr := strconv.FormatInt(taskId, 10)
	_, err = redis.ZAdd(cacheKey, InsIdStr, drawTime)
	if err != nil {
		return
	}

	return
}
